//
//  DispatchSemaphoreDemo.m
//  GCDDemo
//
//  Created by kingboyrang on 2021/10/30.
//  Copyright © 2021 wulanzhou. All rights reserved.
//

#import "DispatchSemaphoreDemo.h"

@interface DispatchSemaphoreDemo (){
    dispatch_semaphore_t semaphoreLock;
}

@property (nonatomic,assign) NSInteger ticketSurplusCount;

@end

@implementation DispatchSemaphoreDemo

/**
 将异步执行任务转换为同步执行任务
 */
- (NSString *)asyncConvertSyncTask1{
    
    __block NSString *taskData= nil;
    
     //(1)创建一个 Semaphore 并初始化信号的总量
     dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
       // 1.请求路径
       NSURL *url = [NSURL URLWithString:@"http://rap2api.taobao.org/app/mock/163155/fankui"];
       // 2.创建请求对象
       NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
       // 3.设置 post 请求方式
       request.HTTPMethod = @"POST";
       // 4.设置请求体
       request.HTTPBody = [@"username=1234&pwd=4321" dataUsingEncoding:NSUTF8StringEncoding];
       NSURLSession *session = [NSURLSession sharedSession];
       NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
           if (error) {
               NSLog(@"NSURLSessionDataTaskerror:%@",error);
               
           }else{
               taskData = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
               //5.解析数据
               NSLog(@"NSURLSessionDataTask:%@",taskData);
           }
           //(2)发送一个信号，让信号总量加 1
           dispatch_semaphore_signal(semaphore);
       }];
       [dataTask resume];
    
    //(3)可以使总信号量减 1，信号总量小于 0 时就会一直等待（阻塞所在线程），否则就可以正常执行。
          dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    return taskData;
}

/**
   保持线程同步,将异步执行任务转换为同步执行任务2
 */
- (void)asyncConvertSyncTask2{
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"semaphore---begin");
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //创建一个 Semaphore 并初始化信号的总量
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    __block int number = 0;
    dispatch_async(queue, ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
        
        number = 100;
        
        //发送一个信号，让信号总量加 1
        dispatch_semaphore_signal(semaphore);
    });
    
    //可以使总信号量减 1，信号总量小于 0 时就会一直等待（阻塞所在线程），否则就可以正常执行。
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"semaphore---end,number = %d",number);
}

/**
 保证线程安全，为线程加锁
 */
- (void)queueLock{
       NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
       NSLog(@"semaphore---begin");
       
       semaphoreLock = dispatch_semaphore_create(1);
       
       self.ticketSurplusCount = 10;
       
       // queue1 代表北京火车票售卖窗口
       dispatch_queue_t queue1 = dispatch_queue_create("net.bujige.testQueue1", DISPATCH_QUEUE_SERIAL);
       // queue2 代表上海火车票售卖窗口
       dispatch_queue_t queue2 = dispatch_queue_create("net.bujige.testQueue2", DISPATCH_QUEUE_SERIAL);
       
       __weak typeof(self) weakSelf = self;
       dispatch_async(queue1, ^{
           [weakSelf saleTicketSafe];
       });
       
       dispatch_async(queue2, ^{
           [weakSelf saleTicketSafe];
       });
}

/**
 * 售卖火车票（线程安全）
 */
- (void)saleTicketSafe {
    while (1) {
        
        NSLog(@"111111111111");
        // 相当于加锁(可以使总信号量减 1)
        dispatch_semaphore_wait(semaphoreLock, DISPATCH_TIME_FOREVER);
        
        if (self.ticketSurplusCount > 0) {  // 如果还有票，继续售卖
            self.ticketSurplusCount--;
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票数：%ld 窗口：%@", (long)self.ticketSurplusCount, [NSThread currentThread]]);
            [NSThread sleepForTimeInterval:0.2];
        } else { // 如果已卖完，关闭售票窗口
            NSLog(@"所有火车票均已售完");
            
            // 相当于解锁(发送一个信号，让信号总量加 1)
            dispatch_semaphore_signal(semaphoreLock);
            break;
        }
        
        // 相当于解锁(发送一个信号，让信号总量加 1)
        dispatch_semaphore_signal(semaphoreLock);
        NSLog(@"222222222222222");
    }
}

/**
 说明：A、B、C、D四个线程，A、B执行完成后才执行C、D,通过信号量控制
 */
- (void)semaphoreTaskQueue{
    
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     //创建一个 Semaphore 并初始化信号的总量
     dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
    
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
         // 追加任务 1
         [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
         NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
        dispatch_semaphore_signal(semaphore);
    });
    
    
    dispatch_async(queue, ^{
         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
         // 追加任务 2
         [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
         NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
         dispatch_semaphore_signal(semaphore);
    });
    
    
    dispatch_async(queue, ^{
         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
         // 追加任务 3
         [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
         NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
         dispatch_semaphore_signal(semaphore);
    });
    
    dispatch_async(queue, ^{
         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
         // 追加任务 4
         [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
         NSLog(@"4---%@",[NSThread currentThread]);      // 打印当前线程
         dispatch_semaphore_signal(semaphore);
    });
    
}

@end
